/*
Copyright [2012] [Maria Eugenia Malagamba]
Copyright [2012] [Leandro Pellegrino]
Copyright [2012] [Julia Gambuzzi]
Copyright [2012] [Ignacio Capodanno]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/

#pragma once
#include <vector>
#include "../Parser/Hidratador.h"
#include "Tablero.h"
#include "../Bonus/GeneradorBonus.h"
#include "../Bonus/BombaDeNeutrones.h"
#include "../Bonus/Bonus.h"
#include "../sockets/Cliente.h"
#include "../sockets/Server.h"
#include <string>
#include <vector>
#include<iostream>
#include "windows.h"

using namespace std;
using namespace Entidades;
using namespace Parser;

class PartidaServidor
{
private:
	Hidratador* hidratador;
	Tablero* tablero;
	vector<string>* imagenes;
	string escenario;
	int navesDeLosClientes[2];
	bool clienteCargoEscenario[2];
	string nombresClientes[2];


	//auxiliares
	bool esPrimerCicloColisionNaves;
	bool esPrimerCicloColisionConBase;
	bool esPrimerCicloColisionConBaseOtroCliente;

	//Movimiento de objetos en escenario.
	void moverNave(vector<int>* colaDeMensajes,Jugador* jugador,Jugador* jugadorContrario,vector<Arma*>* armas,vector<Arma*>* &armasNuevas, vector<bonus_disponibles>* &bonusUsados, float &dt);

	void moverAsteroides(vector<Asteroide*>* &nuevosAsteroides, vector<GeneradorBonus*>* &bonusNuevos,vector<bonus_disponibles>* &bonusCli1,vector<bonus_disponibles>* &bonusCli2);
	void moverArmas(vector<Arma*>* vectorArmas,Jugador* jugadorActual,Jugador* jugadorContrario,vector<Asteroide*>* &nuevosAsteroides,vector<GeneradorBonus*>* &bonusNuevos);
	int moverArmasNuevas(vector<Arma*>* &armasCli1,vector<Asteroide*>* &nuevosAsteroides,vector<GeneradorBonus*>* &bonusNuevos,Jugador* jugadorActual,Jugador* jugadorContrario);
	
	void repararNave(Jugador* jugador, Nave* nave);
	void colisionarNave(Jugador* jugador,vector<bonus_disponibles>* &bonusUsados);
	//bool huboColisionNaveOtroClienteConBase();
	bool huboColisionNaveConBase(Jugador* jugador, Jugador* jugadorContrario);
	bool chequearHayGanador();
	void chequearVidasJugador(Jugador* jugador, vector<bonus_disponibles>* &bonusUsados);
	void explotarBomba(Arma* arma, vector<Asteroide*>* &nuevosAsteroides,vector<GeneradorBonus*>* &bonusNuevos, Jugador* jugador);
	void explotarNeutrones(Nave* nave, Base* base,vector<Asteroide*>* &nuevosAsteroides,vector<GeneradorBonus*>* &bonusNuevos);
	
	bool chequearQuedanAsteroides(vector<Asteroide*>* nuevosAsteroides);
	void agregarAsteroides();

	void eliminarArmasConTiempoDuracionCero();
	void eliminarBonusConTiempoDuracionCero();
	void eliminarAsteroides();

	// START - Funciones de hilos
	typedef struct MyData {
		Server*  server;
		int numeroCliente;
		PartidaServidor* partidaServidor;
	} MYDATA;

	typedef struct EnviarEscenario_Data { 
		PartidaServidor* partidaServidor;
		int numeroDeCliente;
	} ENVIARESCENARIO_DATA;


	static unsigned long __stdcall threadProc(void* ptr){

		MYDATA* pepito = (MYDATA *) ptr;

		//Mientras alla conexiones activas
		while (pepito->server->cantidadConexionesActivas >0){

			int msj = pepito->server->recibirEntero(pepito->numeroCliente);

			if (msj == 999){
				if(pepito->numeroCliente== 0)
					pepito->partidaServidor->terminoCliente1 = true;
				else
					pepito->partidaServidor->terminoCliente2 = true;
				return 0;
			}

			if(msj > 0){

				HANDLE hMutex = CreateMutex(NULL, FALSE, TEXT("colasMutex"));
				DWORD dwWaitResult = WaitForSingleObject(hMutex, INFINITE); 

				if (dwWaitResult == WAIT_OBJECT_0){

					//lo agrego a la cola de mensajes recibidos
					if(pepito->numeroCliente== 0){
						pepito->server->cliente1Listo = true;
						pepito->server->cola1->push_back(msj);
					}else{
						pepito->server->cliente2Listo = true;
						pepito->server->cola2->push_back(msj);
					}
				}
				ReleaseMutex(hMutex);
			}
		}
		return 0;
	}

	bool enviarMensajes(int tamanioMensajeCliente, char* mensajeCliente);

	static DWORD WINAPI EnviarEscenario_StaticThreadStart(void* Param)
	{
		EnviarEscenario_Data* data = (EnviarEscenario_Data*) Param;
		return data->partidaServidor->enviarEscenarioThread(data->numeroDeCliente);
	}
	// END  - Funciones de hilos
	bool enviarEscenarioThread(int numeroDeCliente);

public:
	PartidaServidor(string escenario);

		//para terminar el juego
	bool terminoCliente1;
	bool terminoCliente2;

	Server* servidor;
	int getCantidadDeJugadores();
	int getCantidadMaximaDeJugadores();
	bool enviarEscenario(int numCliente);
	int conectarJugador();
	bool esperarJugadores();
	int prepararPartida(string puerto);

	void armarDatosNave(char* &mensaje, int &posicionMensaje);
	void armarDatosNaveOtroCliente(char* &mensaje, int &posicionMensaje);
	void armarDatosAsteroides(char* &mensaje,int &posicionMensaje,vector<Asteroide*>* &nuevosAsteroides, bool quedanAsteroides);
	int armarDatosAsteroidesBis(char* &mensaje,int &posicionMensaje, vector<Asteroide*>* &nuevosAsteroides, bool quedanAsteroides);
	
	void armarDatosArmas(char* &mensaje,int &posicionMensaje,vector<Arma*>* &armasCli1,vector<Arma*>* &armasCli2);
	void armarDatosJugadores(char* &mensaje,int &posicionMensaje,vector<bonus_disponibles>* &bonusCli1,vector<bonus_disponibles>* &bonusNuevosCli1,vector<bonus_disponibles>* &bonusCli2,vector<bonus_disponibles>* &bonusNuevosCli2);
	void armarDatosBonus(char* &mensaje,int &posicionMensaje,vector<GeneradorBonus*>* &nuevosBonus);
	void armarDatosBonusDefensivos(char* &mensaje,int &posicionMensaje,Nave* nave);

	bool clienteUnoCargoEscenario();
	bool clienteDosCargoEscenario();
	int getNumeroNave(int numeroCliente);
	string getNombreCliente(int numeroCliente);

	void explotarAsteroide(int numeroAsteoride,vector<Asteroide*>* &nuevosAsteroides,vector<GeneradorBonus*>* &bonusNuevos);

	void iniciar();
	~PartidaServidor();
};